package com.demo.function.spring.loadbalancer;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.DefaultResponse;
import org.springframework.cloud.client.loadbalancer.EmptyResponse;
import org.springframework.cloud.client.loadbalancer.Request;
import org.springframework.cloud.client.loadbalancer.Response;
import org.springframework.cloud.loadbalancer.core.ReactorServiceInstanceLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import reactor.core.publisher.Mono;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Random;

/**
 * 灰度负责均衡器，根据请求头标识选择请求服务
 * @author K
 */
@Slf4j
public class GrayLoadBalancer implements ReactorServiceInstanceLoadBalancer {

    /**
     * 服务列表
     */
    private final ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider;

    public GrayLoadBalancer(ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider) {
        this.serviceInstanceListSupplierProvider = serviceInstanceListSupplierProvider;
    }

    @Override
    public Mono<Response<ServiceInstance>> choose(Request request) {
        ServiceInstanceListSupplier supplier = serviceInstanceListSupplierProvider.getIfAvailable();
        if (supplier == null) {
            log.warn("supplier是空，没有服务列表");
            return Mono.just(new EmptyResponse());
        }
        return supplier.get().next().map(this::getInstanceResponse);
    }

    /**
     * 使用随机数获取服务
     * @param instances 服务列表
     * @return 返回请求服务
     */
    private Response<ServiceInstance> getInstanceResponse(List<ServiceInstance> instances) {
        if (instances.isEmpty()) {
            log.warn("没有服务列表");
            return new EmptyResponse();
        }

        log.info("进行选取服务");
        List<ServiceInstance> normalInstances = new ArrayList<>();
        List<ServiceInstance> grayInstances = new ArrayList<>();

        for (ServiceInstance instance : instances) {
            Map<String, String> metadata = instance.getMetadata();
            String flag = metadata.get(GrayRequestContextHolder.GRAY);
            if (Boolean.parseBoolean(flag)) {
                grayInstances.add(instance);
            } else {
                normalInstances.add(instance);
            }
        }

        if (GrayRequestContextHolder.getGray()) {
            log.info("选取灰度服务");
            return choose(grayInstances);
        } else {
            return choose(normalInstances);
        }
    }

    private Response<ServiceInstance> choose(List<ServiceInstance> instances) {
        // 随机算法
        int size = instances.size();
        Random random = new Random();
        ServiceInstance instance = instances.get(random.nextInt(size));
        return new DefaultResponse(instance);
    }
}
